package com.central.post.service.serviceImp

import cn.hutool.core.bean.BeanUtil
import cn.hutool.core.util.StrUtil
import com.baomidou.mybatisplus.extension.kotlin.KtQueryWrapper
import com.baomidou.mybatisplus.extension.plugins.pagination.Page
import com.central.common.entity.Post
import com.central.common.enum.*
import com.central.common.feign.AttentionService
import com.central.common.feign.CommentService
import com.central.common.feign.LikeService
import com.central.common.feign.UserService
import com.central.common.model.*
import com.central.common.service.impl.SuperServiceImpl
import com.central.common.utils.Point2D
import com.central.common.utils.distanceGet
import com.central.common.utils.format
import com.central.common.utils.geocodeRegeo
import com.central.post.mapper.PostMapper
import com.central.post.mq.PostSink
import com.central.post.mq.sendIntegralMes
import com.central.post.mq.sendPostSubscribe
import com.central.post.pojo.post.*
import com.central.post.service.PostService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import java.util.concurrent.CompletableFuture

/**
 * @author  fly
 * @date  2021/5/26 14:51
 * @version 1.0
 */
@Service
open class PostServiceImp : SuperServiceImpl<PostMapper, Post>(), PostService {


    @Autowired
    private lateinit var attentionService: AttentionService

    @Autowired
    private lateinit var userService: UserService

    @Autowired
    private lateinit var likeService: LikeService

    @Autowired
    private lateinit var postSink: PostSink

    @Autowired
    private lateinit var commentService: CommentService


    override fun getPostDetail(id: Long): Post? = getById(id)

    override fun getMyPostLikeNum(userId: Long): Long = list(KtQueryWrapper(Post::class.java)
        .eq(Post::createBy, userId)).takeIf { it.isNotEmpty() }?.run {
            mapNotNull { likeService.getLikeNum(it.id, LikeTypeEnum.POST).likeNum }.reduce { acc, i -> acc + i }.toLong()
    } ?: 0L

    override fun publishTopicPost(
        backPostSaveOrUpdateDto: BackPostSaveOrUpdateDto,
        userId: Long
    ): CommonResult<Boolean> = success(
        saveOrUpdate(Post().apply {
            BeanUtil.copyProperties(backPostSaveOrUpdateDto, this)
            backPostSaveOrUpdateDto.takeIf { it.id != null }?.run { updateBy = userId } ?: kotlin.run { createBy = userId }
        })
    , "操作成功")


    override fun insertOrUpdatePost(postSaveOrUpdateDto: PostSaveOrUpdateDto, sysUser: SysUser): CommonResult<Boolean> {

        val post = Post()
       return saveOrUpdate(post.apply {

            BeanUtil.copyProperties(postSaveOrUpdateDto, this)
            geocodeRegeo(Point2D(postSaveOrUpdateDto.longitude?.toDouble(), postSaveOrUpdateDto.latitude?.toDouble())).let {
                cityCode = it.citycode
                publishAddress = it.formattedAddress
            }
            createBy = sysUser.id
        }).takeIf { it }?.run {

           CompletableFuture.runAsync { postSink.sendIntegralMes(post, null) }.join()
           CompletableFuture.runAsync { postSink.sendPostSubscribe(PostPushParam()
               .apply {
                   id = post.id
                   content = post.content
                   openId = userService.selectByUserId(post.createBy)?.openId
               },
               null) }.join()
           success(true, "操作帖子成功")
        } ?: failed("操作失败")
    }

    override fun getPostList(postDto: PostDto, sysUser: SysUser): CommonResult<Page<PostVo>> {

        val query = KtQueryWrapper(Post::class.java)
        query.like(StrUtil.isNotBlank(postDto.content), Post::content, postDto.content)
            .eq(Post::postType, PostTypeEnum.POST.code)
        when (postDto.type) {
            1 -> attentionService.getMyAttentionIdList(sysUser.id, AttentionTypeEnum.USER)?.run {
                query.`in`(Post::createBy, mapNotNull { it.toLong() })
            } ?: query.eq(Post::id, -1L)

            2 -> query.eq(Post::cityCode, geocodeRegeo(Point2D(postDto.longitude?.toDouble(), postDto.latitude?.toDouble())).citycode!!)

            else -> query.eq(Post::createBy, postDto.userId ?: sysUser.id)
        }

       return page(Page(postDto.pageNum!!, postDto.pageSize!!), query).run {
            records.takeIf { it.isNotEmpty() }?.let {
                success(Page<PostVo>(current, size, total, isSearchCount).apply {
                    records = it.mapNotNull { getPostVo(it, sysUser.id) }
                }, "获取帖子数据成功")
            } ?: failed(ResultCode.NO_CONTENT)
        }

    }

    override fun getPostDetail(postDto: PostDto, sysUser: SysUser): CommonResult<PostVo> = getById(postDto.postId)
        ?.let { success(getPostVo(it, sysUser.id).apply {
            distance = distanceGet(
                Point2D(postDto.longitude?.toDouble(), postDto.latitude?.toDouble()),
                Point2D(it.longitude?.toDouble(), it.latitude?.toDouble()))
            commentCount = commentService.getCommentNumByRelevanceId(postDto.postId!!, CommentTypeEnum.POST)
            commentInfo = commentService.getCommentVoListByRelevanceId(postDto.postId!!, sysUser, PageVo(postDto.pageNum, postDto.pageSize), CommentTypeEnum.POST)
        }, "获取帖子详情成功") }
        ?: failed(ResultCode.NO_CONTENT)

    override fun removePost(id: Long, sysUser: SysUser): CommonResult<Boolean> = getById(id)
        ?.run { success(removeById(this), "移除帖子成功") }
        ?: failed(ResultCode.NO_CONTENT)

    override fun insertOrUpdateTopicPost(topicPostSaveDto: TopicPostSaveDto, sysUser: SysUser): CommonResult<Boolean> {

        val post = Post()
       return save(post.apply {
            BeanUtil.copyProperties(topicPostSaveDto, this)
            postType = PostTypeEnum.TOPIC.code
            geocodeRegeo(Point2D(topicPostSaveDto.longitude?.toDouble(), topicPostSaveDto.latitude?.toDouble())).let {
                cityCode = it.citycode
                publishAddress = it.formattedAddress
            }
            createBy = sysUser.id
        }).takeIf { it }?.run {
            CompletableFuture.runAsync { postSink.sendPostSubscribe(PostPushParam()
                .apply {
                    id = post.id
                    content = post.content
                    openId = userService.selectByUserId(post.createBy)?.openId
                },
                null) }
            success(this, "操作成功")
        } ?: failed("操作失败")
    }

    override fun getTopicDetail(topicId: Long, sysUser: SysUser): CommonResult<TopicPostDetailVo> =
       getById(topicId)?.let {
           success(
               TopicPostDetailVo().apply {
                   BeanUtil.copyProperties(it, this)
                   pics = it.pics?.split(",")
                   list(KtQueryWrapper(Post::class.java).eq(Post::pid,topicId)
                       .eq(Post::postType, PostTypeEnum.TOPIC.code)
                       .orderByDesc(Post::createTime)).takeIf { it.isNotEmpty() }
                       ?.let {
                           replyUserHeadUrl = it.mapNotNull { post ->  userService.selectByUserId(post.createBy)?.headImgUrl }.take(3)
                           postCount = it.size.toLong()
                           totalScore = it.mapNotNull { post -> post.totalScore }.reduce { acc, a -> acc + a }.div(it.size)
                           qualityScore = it.mapNotNull { post -> post.qualityScore }.reduce { acc, b -> acc + b }.div(it.size)
                           liningScore = it.mapNotNull { post -> post.liningScore }.reduce { acc, c -> acc + c }.div(it.size)
                           modelScore = it.mapNotNull { post -> post.modelScore }.reduce { acc, d -> acc + d }.div(it.size)
                           markCount = it.size.toLong()
                       }
                   booleanAttention = attentionService.booleanAttention(it.id, sysUser.id, AttentionTypeEnum.POST)?.booleanAttention
               }
           )
       } ?: failed(ResultCode.NO_CONTENT)

    override fun getAllPostList(type: Int, sysUser: SysUser, pageVo: PageVo): CommonResult<Page<PostVo>> =
        page(Page(pageVo.pageNumber!!, pageVo.pageSize!!), KtQueryWrapper(Post::class.java)
            .orderByDesc(Post::createTime).apply {
                type.takeIf { it == 2 }?.run {
                    eq(Post::createBy, attentionService.getMyAttentionIdList(sysUser.id, AttentionTypeEnum.USER)?.run {
                        mapNotNull { it.toLong() }
                    }).or().eq(Post::id, attentionService.getMyAttentionIdList(sysUser.id, AttentionTypeEnum.POST)?.run {
                        mapNotNull { it.toLong() } })
                }})
            ?.run {
                records?.takeIf { it.isNotEmpty() }?.let {
                    success(
                        Page<PostVo>(current, size, total, isSearchCount).apply {
                            records = it.mapNotNull { getPostVo(it, sysUser.id) }
                        }
                        , "获取帖子列表成功")
                }
            } ?: failed(ResultCode.NO_CONTENT)

    override fun getTopicPostList(topicPostSearchDto: TopicPostSearchDto, pageVo: PageVo, sysUser: SysUser): CommonResult<Page<PostVo>> =
        page(Page(pageVo.pageNumber!!, pageVo.pageSize!!), KtQueryWrapper(Post::class.java)
            .eq(Post::pid, topicPostSearchDto.pid)
            .eq(Post::postType, PostTypeEnum.TOPIC.code)
            .orderByDesc(Post::createTime))
            .run {
                records.takeIf { it.isNotEmpty() }?.let {
                    success(
                        Page<PostVo>(current, size, total, isSearchCount).apply {
                            records = when (topicPostSearchDto.type) {
                                1 -> it.mapNotNull { getPostVo(it, sysUser.id) }
                                else -> it.mapNotNull { getPostVo(it, sysUser.id) }.sortedBy { it.likeCount }
                            }
                            topicPostSearchDto.id?.run {
                                records[1] = getPostVo(getById(this), sysUser.id)
                            }
                        }
                        , "获取话题帖子成功")
                } ?: failed(ResultCode.NO_CONTENT)
            }

    private fun getPostVo(post: Post, userId: Long): PostVo = PostVo().apply {
        BeanUtil.copyProperties(post, this)
        userInfo = UserInfo().apply { BeanUtil.copyProperties(userService.selectByUserId(post.createBy), this) }
        postId = post.id
        pics = post.pics?.split(",")
        createTime = post.createTime.format()
        likeCount = likeService.getLikeNum(post.id, LikeTypeEnum.POST).likeNum
        booleanAttention = attentionService.booleanAttention(post.createBy, userId, AttentionTypeEnum.USER)?.booleanAttention
        booleanLike = likeService.booleanLike(post.id, userId, LikeTypeEnum.POST).booleanLike
        topicContent = post.takeIf { it.pid != 0L && it.postType == PostTypeEnum.TOPIC.code }
            ?.run { getById(post.pid)?.content }
    }

}
